/*******************************************************************************
filename      VariantType.cpp
author        Craig Williams

Brief Description:
  A massive file of copy/paste work that is not that fun to look at. Despite
    this, the following class tends to behave like a variant type should
    behave in my mind. Namely, it supports all standard single element
    data types of C++, with string support. Logical conversion and math is
    performed between all the the different data types, with upcasting
    where necessary.

  Variant Types are far slower then the native built in data types; however,
    they are very nice for FileIO, serialization, and scripting.

  All pointers are used as references (except the void pointer). Some
    serialization functions are provided as well.

  Supported Data Types (signed unsigned, and pointers where applicable):
    void *   bool   char    short   int   long    float   double   long double
    CString

  Supported Math Operations:
    ++ -- -  +  *  / = += -= *= /= !  <  >  <= >= == !=

  Conversion operators between any of the specified data types.

  Any pointer can be cast to a void *, otherwise, the pointer type will be
    preserved. IE, you cannot convert a int * to a unsigned int *.

  Helper Functions:
    SetValue_DontChangeType - Copies the value from one variant into anohter
                                without changing the data type of the current
                                variant.
    ConvertTo  - Converts the internal format to the specified type.
    PopPointer - If the variant holds a pointer, it'll duplicate the content
                   that the pointer is pointing at.
    IsAPointer - Returns true if we are working with a pointer
    IsBool     - Returns true if it is a bool
    IsNumeric  - true if char, short, int, long, float, double, or long double
                   with pointer and unsigned variants included
    IsDecimal  - true if char, short, int, or long with pointer and unsigned
                   variants included
    IsFloat    - true if float, double, or long double with pointer variantions
                   included
    IsString   - true if CString or CString *.
    GetType    - Returns that type the variant is holding.
                   See VARIANT_TYPE_* defines below.
    GetTypeString    - Returns the data type as a human readable string
    SetDecimalOutput - Allows you to specify how deciaml values are converted
                         into strings. Namely,
                           DECIAML - base 10 numbers
                           BINARY  - 0b0101010100
                           OCTAL   - 01234567
                           HEX     - 0x123FFF
                         See VARIANT_DECIMAL_OUTPUT_* define below

  Serialization Functions:
    Pack             - Packs the data into a vector of unsigned chars. The
                         stream is signed for type saftey reasons.
                       Warning: Pointers will be directly written to the stream.
                                  They will still be signed though.
    Unpack           - Attempts to unpack a variant type from the specified
                         vector into the current variant type. This function
                         returns the new index to start reading at.
    UnpackType       - Attempts to read the data type of the next element in
                         the vector.
    UnpackTypeString - Same as UnpackType; however, the data type is then
                         converted into a human readable string.

  Debug Functions:
    Print - Dumps the content of the vector to stdout in the following form:
              "<Type>: <Value>\n"
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>

#include "VariantType.h"

#define OPERATOR_TYPE(type)                                                \
VariantType::operator type(void) const                                     \
{                                                                          \
  switch(mFlags & VARIANT_TYPE)                                            \
  {                                                                        \
    default:                                                               \
    case VARIANT_TYPE_NOT_SET:            return (type) 0;                 \
    case VARIANT_TYPE_VOID_PTR:           return (type) 0;                 \
    case VARIANT_TYPE_VOID:               return (type) 0;                 \
    case VARIANT_TYPE_BOOL_PTR:           return (type)*mType.mBoolPtr;    \
    case VARIANT_TYPE_BOOL:               return (type) mType.mBool;       \
    case VARIANT_TYPE_CHAR_PTR:           return (type)*mType.mCharPtr;    \
    case VARIANT_TYPE_CHAR:               return (type) mType.mChar;       \
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR:  return (type)*mType.mUCharPtr;   \
    case VARIANT_TYPE_UNSIGNED_CHAR:      return (type) mType.mUChar;      \
    case VARIANT_TYPE_SHORT_PTR:          return (type)*mType.mShortPtr;   \
    case VARIANT_TYPE_SHORT:              return (type) mType.mShort;      \
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR: return (type)*mType.mUShortPtr;  \
    case VARIANT_TYPE_UNSIGNED_SHORT:     return (type) mType.mUShort;     \
    case VARIANT_TYPE_INT_PTR:            return (type)*mType.mIntPtr;     \
    case VARIANT_TYPE_INT:                return (type) mType.mInt;        \
    case VARIANT_TYPE_UNSIGNED_INT_PTR:   return (type)*mType.mUIntPtr;    \
    case VARIANT_TYPE_UNSIGNED_INT:       return (type) mType.mUInt;       \
    case VARIANT_TYPE_LONG_PTR:           return (type)*mType.mLongPtr;    \
    case VARIANT_TYPE_LONG:               return (type) mType.mLong;       \
    case VARIANT_TYPE_UNSIGNED_LONG_PTR:  return (type)*mType.mULongPtr;   \
    case VARIANT_TYPE_UNSIGNED_LONG:      return (type) mType.mULong;      \
    case VARIANT_TYPE_FLOAT_PTR:          return (type)*mType.mFloatPtr;   \
    case VARIANT_TYPE_FLOAT:              return (type) mType.mFloat;      \
    case VARIANT_TYPE_DOUBLE_PTR:         return (type)*mType.mDoublePtr;  \
    case VARIANT_TYPE_DOUBLE:             return (type) mType.mDouble;     \
    case VARIANT_TYPE_LONG_DOUBLE_PTR:    return (type)*mType.mLDoublePtr; \
    case VARIANT_TYPE_LONG_DOUBLE:        return (type) mType.mLDouble;    \
                                                                           \
    case VARIANT_TYPE_CSTRING_PTR:        return (type) 0;                 \
    case VARIANT_TYPE_CSTRING:            return (type) 0;                 \
  }                                                                        \
}

#define OPERATOR_TYPE_PTR(type, def)                                           \
VariantType::operator type(void) const                                         \
{                                                                              \
  if((mFlags & VARIANT_TYPE) == def)                                           \
    return (type)(void *)*this;                                                \
  return 0;                                                                    \
}


VariantType::VariantType(void)
{
  mFlags = VARIANT_TYPE_NOT_SET;
}

VariantType::VariantType(void *val)
{
  if(!val){mFlags = VARIANT_TYPE_NOT_SET; return;}
  mFlags = VARIANT_TYPE_VOID_PTR;
  mType.mVoidPtr = val;
}

VariantType::VariantType(bool *val)
{
  if(!val){mFlags = VARIANT_TYPE_NOT_SET; return;}
  mFlags = VARIANT_TYPE_BOOL_PTR;
  mType.mBoolPtr = val;
}

VariantType::VariantType(bool val)
{
  mFlags = VARIANT_TYPE_BOOL;
  mType.mBool = val;
}

VariantType::VariantType(char *val)
{
  if(!val){mFlags = VARIANT_TYPE_NOT_SET; return;}
  mFlags = VARIANT_TYPE_CHAR_PTR;
  mType.mCharPtr = val;
}

VariantType::VariantType(char val)
{
  mFlags = VARIANT_TYPE_CHAR;
  mType.mChar = val;
}

VariantType::VariantType(unsigned char *val)
{
  if(!val){mFlags = VARIANT_TYPE_NOT_SET; return;}
  mFlags = VARIANT_TYPE_UNSIGNED_CHAR_PTR;
  mType.mUCharPtr = val;
}

VariantType::VariantType(unsigned char val)
{
  mFlags = VARIANT_TYPE_UNSIGNED_CHAR;
  mType.mUChar = val;
}

VariantType::VariantType(short *val)
{
  if(!val){mFlags = VARIANT_TYPE_NOT_SET; return;}
  mFlags = VARIANT_TYPE_SHORT_PTR;
  mType.mShortPtr = val;
}

VariantType::VariantType(short val)
{
  mFlags = VARIANT_TYPE_SHORT;
  mType.mShort = val;
}

VariantType::VariantType(unsigned short *val)
{
  if(!val){mFlags = VARIANT_TYPE_NOT_SET; return;}
  mFlags = VARIANT_TYPE_UNSIGNED_SHORT_PTR;
  mType.mUShortPtr = val;
}

VariantType::VariantType(unsigned short val)
{
  mFlags = VARIANT_TYPE_UNSIGNED_SHORT;
  mType.mUShort = val;
}

VariantType::VariantType(int *val)
{
  if(!val){mFlags = VARIANT_TYPE_NOT_SET; return;}
  mFlags = VARIANT_TYPE_INT_PTR;
  mType.mIntPtr = val;
}

VariantType::VariantType(int val)
{
  mFlags = VARIANT_TYPE_INT;
  mType.mInt = val;
}

VariantType::VariantType(unsigned int *val)
{
  if(!val){mFlags = VARIANT_TYPE_NOT_SET; return;}
  mFlags = VARIANT_TYPE_UNSIGNED_INT_PTR;
  mType.mUIntPtr = val;
}

VariantType::VariantType(unsigned int val)
{
  mFlags = VARIANT_TYPE_UNSIGNED_INT;
  mType.mUInt = val;
}

VariantType::VariantType(long *val)
{
  if(!val){mFlags = VARIANT_TYPE_NOT_SET; return;}
  mFlags = VARIANT_TYPE_LONG_PTR;
  mType.mLongPtr = val;
}

VariantType::VariantType(long val)
{
  mFlags = VARIANT_TYPE_LONG;
  mType.mLong = val;
}

VariantType::VariantType(unsigned long *val)
{
  if(!val){mFlags = VARIANT_TYPE_NOT_SET; return;}
  mFlags = VARIANT_TYPE_UNSIGNED_LONG_PTR;
  mType.mULongPtr = val;
}

VariantType::VariantType(unsigned long val)
{
  mFlags = VARIANT_TYPE_UNSIGNED_LONG;
  mType.mULong = val;
}

VariantType::VariantType(float *val)
{
  if(!val){mFlags = VARIANT_TYPE_NOT_SET; return;}
  mFlags = VARIANT_TYPE_FLOAT_PTR;
  mType.mFloatPtr = val;
}

VariantType::VariantType(float val)
{
  mFlags = VARIANT_TYPE_FLOAT;
  mType.mFloat = val;
}

VariantType::VariantType(double *val)
{
  if(!val){mFlags = VARIANT_TYPE_NOT_SET; return;}
  mFlags = VARIANT_TYPE_DOUBLE_PTR;
  mType.mDoublePtr = val;
}

VariantType::VariantType(double val)
{
  mFlags = VARIANT_TYPE_DOUBLE;
  mType.mDouble = val;
}

VariantType::VariantType(long double *val)
{
  if(!val){mFlags = VARIANT_TYPE_NOT_SET; return;}
  mFlags = VARIANT_TYPE_LONG_DOUBLE_PTR;
  mType.mLDoublePtr = val;
}

VariantType::VariantType(long double val)
{
  mFlags = VARIANT_TYPE_LONG_DOUBLE;
  mType.mLDouble = val;
}

VariantType::VariantType(const char *val)
{
  mFlags = 0;
  if(val)
    BuildString(CString(val));
}

VariantType::VariantType(const CString &val)
{
  mFlags = 0;
  BuildString(val);
}

VariantType::VariantType(CString *val)
{
  mFlags = 0;
  if(val)
    BuildString(val);
}

VariantType::VariantType(const VariantType &rval)
{
  mFlags = 0;
  *this = rval;
}

VariantType::~VariantType(void)
{
  DestroyString();
}


VariantType &VariantType::operator++(void)
{
  switch(mFlags & VARIANT_TYPE)
  {
    default:
    case VARIANT_TYPE_NOT_SET:                                          break;
    case VARIANT_TYPE_VOID_PTR:                                         break;
    case VARIANT_TYPE_VOID:                                             break;
    case VARIANT_TYPE_BOOL_PTR:             *mType.mBoolPtr = 1;        break;
    case VARIANT_TYPE_BOOL:                  mType.mBool    = 1;        break;
    case VARIANT_TYPE_CHAR_PTR:           ++*mType.mCharPtr;            break;
    case VARIANT_TYPE_CHAR:               ++ mType.mChar;               break;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR:  ++*mType.mUCharPtr;           break;
    case VARIANT_TYPE_UNSIGNED_CHAR:      ++ mType.mUChar;              break;
    case VARIANT_TYPE_SHORT_PTR:          ++*mType.mShortPtr;           break;
    case VARIANT_TYPE_SHORT:              ++ mType.mShort;              break;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR: ++*mType.mUShortPtr;          break;
    case VARIANT_TYPE_UNSIGNED_SHORT:     ++ mType.mUShort;             break;
    case VARIANT_TYPE_INT_PTR:            ++*mType.mIntPtr;             break;
    case VARIANT_TYPE_INT:                ++ mType.mInt;                break;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:   ++*mType.mUIntPtr;            break;
    case VARIANT_TYPE_UNSIGNED_INT:       ++ mType.mUInt;               break;
    case VARIANT_TYPE_LONG_PTR:           ++*mType.mLongPtr;            break;
    case VARIANT_TYPE_LONG:               ++ mType.mLong;               break;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR:  ++*mType.mULongPtr;           break;
    case VARIANT_TYPE_UNSIGNED_LONG:      ++ mType.mULong;              break;
    case VARIANT_TYPE_FLOAT_PTR:            *mType.mFloatPtr   += 1.0f; break;
    case VARIANT_TYPE_FLOAT:                 mType.mFloat      += 1.0f; break;
    case VARIANT_TYPE_DOUBLE_PTR:           *mType.mDoublePtr  += 1.0;  break;
    case VARIANT_TYPE_DOUBLE:                mType.mDouble     += 1.0;  break;
    case VARIANT_TYPE_LONG_DOUBLE_PTR:      *mType.mLDoublePtr += 1.0;  break;
    case VARIANT_TYPE_LONG_DOUBLE:           mType.mLDouble    += 1.0;  break;

    case VARIANT_TYPE_CSTRING_PTR:                                      break;
    case VARIANT_TYPE_CSTRING:                                          break;
  }

  return *this;
}

VariantType VariantType::operator++(int) // Post Increment
{
  VariantType ret(*this);
  ret.PopPointer();
  ++(*this);
  return ret;
}

VariantType &VariantType::operator--(void)
{
  switch(mFlags & VARIANT_TYPE)
  {
    default:
    case VARIANT_TYPE_NOT_SET:                                          break;
    case VARIANT_TYPE_VOID_PTR:                                         break;
    case VARIANT_TYPE_VOID:                                             break;
    case VARIANT_TYPE_BOOL_PTR:             *mType.mBoolPtr = 0;        break;
    case VARIANT_TYPE_BOOL:                  mType.mBool    = 0;        break;
    case VARIANT_TYPE_CHAR_PTR:           --*mType.mCharPtr;            break;
    case VARIANT_TYPE_CHAR:               -- mType.mChar;               break;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR:  --*mType.mUCharPtr;           break;
    case VARIANT_TYPE_UNSIGNED_CHAR:      -- mType.mUChar;              break;
    case VARIANT_TYPE_SHORT_PTR:          --*mType.mShortPtr;           break;
    case VARIANT_TYPE_SHORT:              -- mType.mShort;              break;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR: --*mType.mUShortPtr;          break;
    case VARIANT_TYPE_UNSIGNED_SHORT:     -- mType.mUShort;             break;
    case VARIANT_TYPE_INT_PTR:            --*mType.mIntPtr;             break;
    case VARIANT_TYPE_INT:                -- mType.mInt;                break;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:   --*mType.mUIntPtr;            break;
    case VARIANT_TYPE_UNSIGNED_INT:       -- mType.mUInt;               break;
    case VARIANT_TYPE_LONG_PTR:           --*mType.mLongPtr;            break;
    case VARIANT_TYPE_LONG:               -- mType.mLong;               break;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR:  --*mType.mULongPtr;           break;
    case VARIANT_TYPE_UNSIGNED_LONG:      -- mType.mULong;              break;
    case VARIANT_TYPE_FLOAT_PTR:            *mType.mFloatPtr   -= 1.0f; break;
    case VARIANT_TYPE_FLOAT:                 mType.mFloat      -= 1.0f; break;
    case VARIANT_TYPE_DOUBLE_PTR:           *mType.mDoublePtr  -= 1.0;  break;
    case VARIANT_TYPE_DOUBLE:                mType.mDouble     -= 1.0;  break;
    case VARIANT_TYPE_LONG_DOUBLE_PTR:      *mType.mLDoublePtr -= 1.0;  break;
    case VARIANT_TYPE_LONG_DOUBLE:           mType.mLDouble    -= 1.0;  break;

    case VARIANT_TYPE_CSTRING_PTR:                                      break;
    case VARIANT_TYPE_CSTRING:                                          break;
  }

  return *this;
}

VariantType VariantType::operator--(int) // Post Decrement
{
  VariantType ret(*this);
  ret.PopPointer();
  --(*this);
  return ret;
}

VariantType VariantType::operator-(void) const // Negation
{
  VariantType ret(*this);
  ret.PopPointer();

  switch(mFlags & VARIANT_TYPE)
  {
    default:
    case VARIANT_TYPE_NOT_SET:                                                                break;
    case VARIANT_TYPE_VOID_PTR:                                                               break;
    case VARIANT_TYPE_VOID:                                                                   break;
    case VARIANT_TYPE_BOOL_PTR:           *ret.mType.mBoolPtr    = !*ret.mType.mBoolPtr;      break;
    case VARIANT_TYPE_BOOL:                ret.mType.mBool       = ! ret.mType.mBool;         break;
    case VARIANT_TYPE_CHAR_PTR:           *ret.mType.mCharPtr    = -*ret.mType.mCharPtr;      break;
    case VARIANT_TYPE_CHAR:                ret.mType.mChar       = - ret.mType.mChar;         break;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR:  *ret.mType.mUCharPtr   = -*ret.mType.mUCharPtr;     break;
    case VARIANT_TYPE_UNSIGNED_CHAR:       ret.mType.mUChar      = - ret.mType.mUChar;        break;
    case VARIANT_TYPE_SHORT_PTR:          *ret.mType.mShortPtr   = -*ret.mType.mShortPtr;     break;
    case VARIANT_TYPE_SHORT:               ret.mType.mShort      = - ret.mType.mShort;        break;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR: *ret.mType.mUShortPtr  = -*ret.mType.mUShortPtr;    break;
    case VARIANT_TYPE_UNSIGNED_SHORT:      ret.mType.mUShort     = - ret.mType.mUShort;       break;
    case VARIANT_TYPE_INT_PTR:            *ret.mType.mIntPtr     = -*ret.mType.mIntPtr;       break;
    case VARIANT_TYPE_INT:                 ret.mType.mInt        = - ret.mType.mInt;          break;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:   *ret.mType.mUIntPtr    = -(int)*ret.mType.mUIntPtr; break;
    case VARIANT_TYPE_UNSIGNED_INT:        ret.mType.mUInt       = -(int) ret.mType.mUInt;    break;
    case VARIANT_TYPE_LONG_PTR:           *ret.mType.mLongPtr    = -*ret.mType.mLongPtr;      break;
    case VARIANT_TYPE_LONG:                ret.mType.mLong       = - ret.mType.mLong;         break;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR:  *ret.mType.mULongPtr   = -(int)*ret.mType.mULongPtr;break;
    case VARIANT_TYPE_UNSIGNED_LONG:       ret.mType.mULong      = -(int) ret.mType.mULong;   break;
    case VARIANT_TYPE_FLOAT_PTR:          *ret.mType.mFloatPtr   = -*ret.mType.mFloatPtr;     break;
    case VARIANT_TYPE_FLOAT:               ret.mType.mFloat      = - ret.mType.mFloat;        break;
    case VARIANT_TYPE_DOUBLE_PTR:         *ret.mType.mDoublePtr  = -*ret.mType.mDoublePtr;    break;
    case VARIANT_TYPE_DOUBLE:              ret.mType.mDouble     = - ret.mType.mDouble;       break;
    case VARIANT_TYPE_LONG_DOUBLE_PTR:    *ret.mType.mLDoublePtr = -*ret.mType.mLDoublePtr;   break;
    case VARIANT_TYPE_LONG_DOUBLE:         ret.mType.mLDouble    = - ret.mType.mLDouble;      break;

    case VARIANT_TYPE_CSTRING_PTR: break;
    case VARIANT_TYPE_CSTRING:     break;
  }

  return ret;
}

VariantType VariantType::operator+(const VariantType &rval) const
{
  if((mFlags & VARIANT_TYPE) < (rval.mFlags & VARIANT_TYPE))
    return rval + *this;

  return VariantType(*this).PopPointer() += rval;
}

VariantType VariantType::operator-(const VariantType &rval) const
{
  unsigned int sign = 0;;
  VariantType l(*this);
  VariantType r(rval);

  l.PopPointer();
  r.PopPointer();

  if((l.mFlags & VARIANT_TYPE) < (r.mFlags & VARIANT_TYPE))
  {
    if(!r.IsSigned())
      r.ConvertTo((r.mFlags & VARIANT_TYPE) + 2);
    return -r + l;
  }

  if(!l.IsSigned() && r.IsSigned())
    l.ConvertTo((l.mFlags & VARIANT_TYPE) + 2);

  return l -= r;
}

VariantType VariantType::operator*(const VariantType &rval) const
{
  if((mFlags & VARIANT_TYPE) < (rval.mFlags & VARIANT_TYPE))
    return rval * *this;

  return VariantType(*this).PopPointer() *= rval;
}

VariantType VariantType::operator/(const VariantType &rval) const
{
  VariantType ret(*this);
  ret.PopPointer();
  if((mFlags & VARIANT_TYPE) < (rval.mFlags & VARIANT_TYPE))
    ret.ConvertTo(rval.mFlags & VARIANT_TYPE);

  return ret /= rval;
}

VariantType &VariantType::operator=(const VariantType &rval)
{
  if(IsAPointer())
    return SetValue_DontChangeType(rval);

  DestroyString();

  if((rval.mFlags & VARIANT_TYPE) == VARIANT_TYPE_CSTRING_PTR)
    BuildString(rval.mType.mStr.Ptr);
  else
  if((rval.mFlags & VARIANT_TYPE) == VARIANT_TYPE_CSTRING)
    BuildString(*(CString *)rval.mType.mStr.Raw);
  else
  {
      // Coping pointers is safe here.
    mFlags = rval.mFlags;
    mType  = rval.mType;
  }

    // TODO: Handle Special Cases
  return *this;
}

VariantType &VariantType::operator+=(const VariantType &rval)
{
  switch(mFlags & VARIANT_TYPE)
  {
    default:
    case VARIANT_TYPE_NOT_SET:           *this = rval;                             break;
    case VARIANT_TYPE_VOID_PTR:                                                    break;
    case VARIANT_TYPE_VOID:                                                        break;
    case VARIANT_TYPE_BOOL_PTR:          if((bool)rval)*mType.mBoolPtr = 1;        break;
    case VARIANT_TYPE_BOOL:              if((bool)rval) mType.mBool    = 1;        break;
    case VARIANT_TYPE_CHAR_PTR:          *mType.mCharPtr   += (char)          rval;break;
    case VARIANT_TYPE_CHAR:               mType.mChar      += (char)          rval;break;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR: *mType.mUCharPtr  += (unsigned char) rval;break;
    case VARIANT_TYPE_UNSIGNED_CHAR:      mType.mUChar     += (unsigned char) rval;break;
    case VARIANT_TYPE_SHORT_PTR:         *mType.mShortPtr  += (short)         rval;break;
    case VARIANT_TYPE_SHORT:              mType.mShort     += (short)         rval;break;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR:*mType.mUShortPtr += (unsigned short)rval;break;
    case VARIANT_TYPE_UNSIGNED_SHORT:     mType.mUShort    += (unsigned short)rval;break;
    case VARIANT_TYPE_INT_PTR:           *mType.mIntPtr    += (int)           rval;break;
    case VARIANT_TYPE_INT:                mType.mInt       += (int)           rval;break;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:  *mType.mUIntPtr   += (unsigned int)  rval;break;
    case VARIANT_TYPE_UNSIGNED_INT:       mType.mUInt      += (unsigned int)  rval;break;
    case VARIANT_TYPE_LONG_PTR:          *mType.mLongPtr   += (long)          rval;break;
    case VARIANT_TYPE_LONG:               mType.mLong      += (long)          rval;break;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR: *mType.mULongPtr  += (unsigned long) rval;break;
    case VARIANT_TYPE_UNSIGNED_LONG:      mType.mULong     += (unsigned long) rval;break;
    case VARIANT_TYPE_FLOAT_PTR:         *mType.mFloatPtr  += (float)         rval;break;
    case VARIANT_TYPE_FLOAT:              mType.mFloat     += (float)         rval;break;
    case VARIANT_TYPE_DOUBLE_PTR:        *mType.mDoublePtr += (double)        rval;break;
    case VARIANT_TYPE_DOUBLE:             mType.mDouble    += (double)        rval;break;
    case VARIANT_TYPE_LONG_DOUBLE_PTR:   *mType.mLDoublePtr+= (long double)   rval;break;
    case VARIANT_TYPE_LONG_DOUBLE:        mType.mLDouble   += (long double)   rval;break;

    case VARIANT_TYPE_CSTRING_PTR:
      *mType.mStr.Ptr += (CString)rval;
      break;
    case VARIANT_TYPE_CSTRING:
      *((CString *)mType.mStr.Raw) += (CString)rval;
      break;
  }

  return *this;
}

VariantType &VariantType::operator-=(const VariantType &rval)
{
  switch(mFlags & VARIANT_TYPE)
  {
    default:
    case VARIANT_TYPE_NOT_SET:           *this = rval;                             break;
    case VARIANT_TYPE_VOID_PTR:                                                    break;
    case VARIANT_TYPE_VOID:                                                        break;
    case VARIANT_TYPE_BOOL_PTR:          if((bool)rval)*mType.mBoolPtr = 0;        break;
    case VARIANT_TYPE_BOOL:              if((bool)rval) mType.mBool    = 0;        break;
    case VARIANT_TYPE_CHAR_PTR:          *mType.mCharPtr   -= (char)          rval;break;
    case VARIANT_TYPE_CHAR:               mType.mChar      -= (char)          rval;break;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR: *mType.mUCharPtr  -= (unsigned char) rval;break;
    case VARIANT_TYPE_UNSIGNED_CHAR:      mType.mUChar     -= (unsigned char) rval;break;
    case VARIANT_TYPE_SHORT_PTR:         *mType.mShortPtr  -= (short)         rval;break;
    case VARIANT_TYPE_SHORT:              mType.mShort     -= (short)         rval;break;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR:*mType.mUShortPtr -= (unsigned short)rval;break;
    case VARIANT_TYPE_UNSIGNED_SHORT:     mType.mUShort    -= (unsigned short)rval;break;
    case VARIANT_TYPE_INT_PTR:           *mType.mIntPtr    -= (int)           rval;break;
    case VARIANT_TYPE_INT:                mType.mInt       -= (int)           rval;break;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:  *mType.mUIntPtr   -= (unsigned int)  rval;break;
    case VARIANT_TYPE_UNSIGNED_INT:       mType.mUInt      -= (unsigned int)  rval;break;
    case VARIANT_TYPE_LONG_PTR:          *mType.mLongPtr   -= (long)          rval;break;
    case VARIANT_TYPE_LONG:               mType.mLong      -= (long)          rval;break;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR: *mType.mULongPtr  -= (unsigned long) rval;break;
    case VARIANT_TYPE_UNSIGNED_LONG:      mType.mULong     -= (unsigned long) rval;break;
    case VARIANT_TYPE_FLOAT_PTR:         *mType.mFloatPtr  -= (float)         rval;break;
    case VARIANT_TYPE_FLOAT:              mType.mFloat     -= (float)         rval;break;
    case VARIANT_TYPE_DOUBLE_PTR:        *mType.mDoublePtr -= (double)        rval;break;
    case VARIANT_TYPE_DOUBLE:             mType.mDouble    -= (double)        rval;break;
    case VARIANT_TYPE_LONG_DOUBLE_PTR:   *mType.mLDoublePtr-= (long double)   rval;break;
    case VARIANT_TYPE_LONG_DOUBLE:        mType.mLDouble   -= (long double)   rval;break;

    case VARIANT_TYPE_CSTRING_PTR: break;
    case VARIANT_TYPE_CSTRING:     break;
  }

  return *this;
}

VariantType &VariantType::operator*=(const VariantType &rval)
{
  switch(mFlags & VARIANT_TYPE)
  {
    default:
    case VARIANT_TYPE_NOT_SET:           *this = rval;                             break;
    case VARIANT_TYPE_VOID_PTR:                                                    break;
    case VARIANT_TYPE_VOID:                                                        break;
    case VARIANT_TYPE_BOOL_PTR:          if(!(bool)rval)*mType.mBoolPtr = 0;       break;
    case VARIANT_TYPE_BOOL:              if(!(bool)rval) mType.mBool    = 0;       break;
    case VARIANT_TYPE_CHAR_PTR:          *mType.mCharPtr   *= (char)          rval;break;
    case VARIANT_TYPE_CHAR:               mType.mChar      *= (char)          rval;break;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR: *mType.mUCharPtr  *= (unsigned char) rval;break;
    case VARIANT_TYPE_UNSIGNED_CHAR:      mType.mUChar     *= (unsigned char) rval;break;
    case VARIANT_TYPE_SHORT_PTR:         *mType.mShortPtr  *= (short)         rval;break;
    case VARIANT_TYPE_SHORT:              mType.mShort     *= (short)         rval;break;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR:*mType.mUShortPtr *= (unsigned short)rval;break;
    case VARIANT_TYPE_UNSIGNED_SHORT:     mType.mUShort    *= (unsigned short)rval;break;
    case VARIANT_TYPE_INT_PTR:           *mType.mIntPtr    *= (int)           rval;break;
    case VARIANT_TYPE_INT:                mType.mInt       *= (int)           rval;break;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:  *mType.mUIntPtr   *= (unsigned int)  rval;break;
    case VARIANT_TYPE_UNSIGNED_INT:       mType.mUInt      *= (unsigned int)  rval;break;
    case VARIANT_TYPE_LONG_PTR:          *mType.mLongPtr   *= (long)          rval;break;
    case VARIANT_TYPE_LONG:               mType.mLong      *= (long)          rval;break;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR: *mType.mULongPtr  *= (unsigned long) rval;break;
    case VARIANT_TYPE_UNSIGNED_LONG:      mType.mULong     *= (unsigned long) rval;break;
    case VARIANT_TYPE_FLOAT_PTR:         *mType.mFloatPtr  *= (float)         rval;break;
    case VARIANT_TYPE_FLOAT:              mType.mFloat     *= (float)         rval;break;
    case VARIANT_TYPE_DOUBLE_PTR:        *mType.mDoublePtr *= (double)        rval;break;
    case VARIANT_TYPE_DOUBLE:             mType.mDouble    *= (double)        rval;break;
    case VARIANT_TYPE_LONG_DOUBLE_PTR:   *mType.mLDoublePtr*= (long double)   rval;break;
    case VARIANT_TYPE_LONG_DOUBLE:        mType.mLDouble   *= (long double)   rval;break;

    case VARIANT_TYPE_CSTRING_PTR: break;
    case VARIANT_TYPE_CSTRING:     break;
  }

  return *this;
}

VariantType &VariantType::operator/=(const VariantType &rval)
{
  switch(mFlags & VARIANT_TYPE)
  {
    default:
    case VARIANT_TYPE_NOT_SET:           *this = rval;                             break;
    case VARIANT_TYPE_VOID_PTR:                                                    break;
    case VARIANT_TYPE_VOID:                                                        break;
    case VARIANT_TYPE_BOOL_PTR:          if(!(bool)rval)*mType.mBoolPtr = 0;       break;
    case VARIANT_TYPE_BOOL:              if(!(bool)rval) mType.mBool    = 0;       break;
    case VARIANT_TYPE_CHAR_PTR:          *mType.mCharPtr   /= (char)          rval;break;
    case VARIANT_TYPE_CHAR:               mType.mChar      /= (char)          rval;break;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR: *mType.mUCharPtr  /= (unsigned char) rval;break;
    case VARIANT_TYPE_UNSIGNED_CHAR:      mType.mUChar     /= (unsigned char) rval;break;
    case VARIANT_TYPE_SHORT_PTR:         *mType.mShortPtr  /= (short)         rval;break;
    case VARIANT_TYPE_SHORT:              mType.mShort     /= (short)         rval;break;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR:*mType.mUShortPtr /= (unsigned short)rval;break;
    case VARIANT_TYPE_UNSIGNED_SHORT:     mType.mUShort    /= (unsigned short)rval;break;
    case VARIANT_TYPE_INT_PTR:           *mType.mIntPtr    /= (int)           rval;break;
    case VARIANT_TYPE_INT:                mType.mInt       /= (int)           rval;break;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:  *mType.mUIntPtr   /= (unsigned int)  rval;break;
    case VARIANT_TYPE_UNSIGNED_INT:       mType.mUInt      /= (unsigned int)  rval;break;
    case VARIANT_TYPE_LONG_PTR:          *mType.mLongPtr   /= (long)          rval;break;
    case VARIANT_TYPE_LONG:               mType.mLong      /= (long)          rval;break;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR: *mType.mULongPtr  /= (unsigned long) rval;break;
    case VARIANT_TYPE_UNSIGNED_LONG:      mType.mULong     /= (unsigned long) rval;break;
    case VARIANT_TYPE_FLOAT_PTR:         *mType.mFloatPtr  /= (float)         rval;break;
    case VARIANT_TYPE_FLOAT:              mType.mFloat     /= (float)         rval;break;
    case VARIANT_TYPE_DOUBLE_PTR:        *mType.mDoublePtr /= (double)        rval;break;
    case VARIANT_TYPE_DOUBLE:             mType.mDouble    /= (double)        rval;break;
    case VARIANT_TYPE_LONG_DOUBLE_PTR:   *mType.mLDoublePtr/= (long double)   rval;break;
    case VARIANT_TYPE_LONG_DOUBLE:        mType.mLDouble   /= (long double)   rval;break;

    case VARIANT_TYPE_CSTRING_PTR: break;
    case VARIANT_TYPE_CSTRING:     break;
  }

  return *this;
}

bool VariantType::operator!(void) const
{
  return !(bool)*this;
}

bool VariantType::operator<(const VariantType &rval) const
{
  return !(*this >= rval);
}

bool VariantType::operator>(const VariantType &rval) const
{
  return !(*this <= rval);
}

bool VariantType::operator<=(const VariantType &rval) const
{
  if((mFlags & VARIANT_TYPE) < (rval.mFlags & VARIANT_TYPE))
    return rval >= *this;

  switch(mFlags & VARIANT_TYPE)
  {
    default:
    case VARIANT_TYPE_NOT_SET:           return (rval.mFlags & VARIANT_TYPE) == VARIANT_TYPE_NOT_SET;
    case VARIANT_TYPE_VOID_PTR:          return  mType.mVoidPtr   <=(void *)        rval;
    case VARIANT_TYPE_VOID:              return  0;
    case VARIANT_TYPE_BOOL_PTR:          return *mType.mBoolPtr   <=(bool)          rval;
    case VARIANT_TYPE_BOOL:              return  mType.mBool      <=(bool)          rval;
    case VARIANT_TYPE_CHAR_PTR:          return *mType.mCharPtr   <=(char)          rval;
    case VARIANT_TYPE_CHAR:              return  mType.mChar      <=(char)          rval;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR: return *mType.mUCharPtr  <=(unsigned char) rval;
    case VARIANT_TYPE_UNSIGNED_CHAR:     return  mType.mUChar     <=(unsigned char) rval;
    case VARIANT_TYPE_SHORT_PTR:         return *mType.mShortPtr  <=(short)         rval;
    case VARIANT_TYPE_SHORT:             return  mType.mShort     <=(short)         rval;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR:return *mType.mUShortPtr <=(unsigned short)rval;
    case VARIANT_TYPE_UNSIGNED_SHORT:    return  mType.mUShort    <=(unsigned short)rval;
    case VARIANT_TYPE_INT_PTR:           return *mType.mIntPtr    <=(int)           rval;
    case VARIANT_TYPE_INT:               return  mType.mInt       <=(int)           rval;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:  return *mType.mUIntPtr   <=(unsigned int)  rval;
    case VARIANT_TYPE_UNSIGNED_INT:      return  mType.mUInt      <=(unsigned int)  rval;
    case VARIANT_TYPE_LONG_PTR:          return *mType.mLongPtr   <=(long)          rval;
    case VARIANT_TYPE_LONG:              return  mType.mLong      <=(long)          rval;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR: return *mType.mULongPtr  <=(unsigned long) rval;
    case VARIANT_TYPE_UNSIGNED_LONG:     return  mType.mULong     <=(unsigned long) rval;
    case VARIANT_TYPE_FLOAT_PTR:         return *mType.mFloatPtr  <=(float)         rval;
    case VARIANT_TYPE_FLOAT:             return  mType.mFloat     <=(float)         rval;
    case VARIANT_TYPE_DOUBLE_PTR:        return *mType.mDoublePtr <=(double)        rval;
    case VARIANT_TYPE_DOUBLE:            return  mType.mDouble    <=(double)        rval;
    case VARIANT_TYPE_LONG_DOUBLE_PTR:   return *mType.mLDoublePtr<=(long double)   rval;
    case VARIANT_TYPE_LONG_DOUBLE:       return  mType.mLDouble   <=(long double)   rval;

    case VARIANT_TYPE_CSTRING_PTR:
      return *(mType.mStr.Ptr) <= (CString)rval;
      break;
    case VARIANT_TYPE_CSTRING:
      return *((CString *)mType.mStr.Raw) <= (CString)rval;
      break;
  }
}

bool VariantType::operator>=(const VariantType &rval) const
{
  if((mFlags & VARIANT_TYPE) < (rval.mFlags & VARIANT_TYPE))
    return rval <= *this;

  switch(mFlags & VARIANT_TYPE)
  {
    default:
    case VARIANT_TYPE_NOT_SET:           return (rval.mFlags & VARIANT_TYPE) == VARIANT_TYPE_NOT_SET;
    case VARIANT_TYPE_VOID_PTR:          return  mType.mVoidPtr   >=(void *)        rval;
    case VARIANT_TYPE_VOID:              return  0;
    case VARIANT_TYPE_BOOL_PTR:          return *mType.mBoolPtr   >=(bool)          rval;
    case VARIANT_TYPE_BOOL:              return  mType.mBool      >=(bool)          rval;
    case VARIANT_TYPE_CHAR_PTR:          return *mType.mCharPtr   >=(char)          rval;
    case VARIANT_TYPE_CHAR:              return  mType.mChar      >=(char)          rval;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR: return *mType.mUCharPtr  >=(unsigned char) rval;
    case VARIANT_TYPE_UNSIGNED_CHAR:     return  mType.mUChar     >=(unsigned char) rval;
    case VARIANT_TYPE_SHORT_PTR:         return *mType.mShortPtr  >=(short)         rval;
    case VARIANT_TYPE_SHORT:             return  mType.mShort     >=(short)         rval;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR:return *mType.mUShortPtr >=(unsigned short)rval;
    case VARIANT_TYPE_UNSIGNED_SHORT:    return  mType.mUShort    >=(unsigned short)rval;
    case VARIANT_TYPE_INT_PTR:           return *mType.mIntPtr    >=(int)           rval;
    case VARIANT_TYPE_INT:               return  mType.mInt       >=(int)           rval;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:  return *mType.mUIntPtr   >=(unsigned int)  rval;
    case VARIANT_TYPE_UNSIGNED_INT:      return  mType.mUInt      >=(unsigned int)  rval;
    case VARIANT_TYPE_LONG_PTR:          return *mType.mLongPtr   >=(long)          rval;
    case VARIANT_TYPE_LONG:              return  mType.mLong      >=(long)          rval;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR: return *mType.mULongPtr  >=(unsigned long) rval;
    case VARIANT_TYPE_UNSIGNED_LONG:     return  mType.mULong     >=(unsigned long) rval;
    case VARIANT_TYPE_FLOAT_PTR:         return *mType.mFloatPtr  >=(float)         rval;
    case VARIANT_TYPE_FLOAT:             return  mType.mFloat     >=(float)         rval;
    case VARIANT_TYPE_DOUBLE_PTR:        return *mType.mDoublePtr >=(double)        rval;
    case VARIANT_TYPE_DOUBLE:            return  mType.mDouble    >=(double)        rval;
    case VARIANT_TYPE_LONG_DOUBLE_PTR:   return *mType.mLDoublePtr>=(long double)   rval;
    case VARIANT_TYPE_LONG_DOUBLE:       return  mType.mLDouble   >=(long double)   rval;

    case VARIANT_TYPE_CSTRING_PTR:
      return *(mType.mStr.Ptr) >= (CString)rval;
      break;
    case VARIANT_TYPE_CSTRING:
      return *((CString *)mType.mStr.Raw) >= (CString)rval;
      break;
  }
}

bool VariantType::operator==(const VariantType &rval) const
{
  if((mFlags & VARIANT_TYPE) < (rval.mFlags & VARIANT_TYPE))
    return rval == *this;

  switch(mFlags & VARIANT_TYPE)
  {
    default:
    case VARIANT_TYPE_NOT_SET:           return (rval.mFlags & VARIANT_TYPE) == VARIANT_TYPE_NOT_SET;
    case VARIANT_TYPE_VOID_PTR:          return mType.mVoidPtr    ==(void *)        rval;
    case VARIANT_TYPE_VOID:              return 0;
    case VARIANT_TYPE_BOOL_PTR:          return *mType.mBoolPtr   ==(bool)          rval;
    case VARIANT_TYPE_BOOL:              return  mType.mBool      ==(bool)          rval;
    case VARIANT_TYPE_CHAR_PTR:          return *mType.mCharPtr   ==(char)          rval;
    case VARIANT_TYPE_CHAR:              return  mType.mChar      ==(char)          rval;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR: return *mType.mUCharPtr  ==(unsigned char) rval;
    case VARIANT_TYPE_UNSIGNED_CHAR:     return  mType.mUChar     ==(unsigned char) rval;
    case VARIANT_TYPE_SHORT_PTR:         return *mType.mShortPtr  ==(short)         rval;
    case VARIANT_TYPE_SHORT:             return  mType.mShort     ==(short)         rval;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR:return *mType.mUShortPtr ==(unsigned short)rval;
    case VARIANT_TYPE_UNSIGNED_SHORT:    return  mType.mUShort    ==(unsigned short)rval;
    case VARIANT_TYPE_INT_PTR:           return *mType.mIntPtr    ==(int)           rval;
    case VARIANT_TYPE_INT:               return  mType.mInt       ==(int)           rval;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:  return *mType.mUIntPtr   ==(unsigned int)  rval;
    case VARIANT_TYPE_UNSIGNED_INT:      return  mType.mUInt      ==(unsigned int)  rval;
    case VARIANT_TYPE_LONG_PTR:          return *mType.mLongPtr   ==(long)          rval;
    case VARIANT_TYPE_LONG:              return  mType.mLong      ==(long)          rval;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR: return *mType.mULongPtr  ==(unsigned long) rval;
    case VARIANT_TYPE_UNSIGNED_LONG:     return  mType.mULong     ==(unsigned long) rval;

    case VARIANT_TYPE_FLOAT_PTR:
      {
        float  delta  = *mType.mFloatPtr - (float)rval;
        return delta >= -0.00001f && delta <= 0.00001f;
      }
    case VARIANT_TYPE_FLOAT:
      {
        float  delta  = mType.mFloat - (float)rval;
        return delta >= -0.00001f && delta <= 0.00001f;
      }

    case VARIANT_TYPE_DOUBLE_PTR:
      {
        double delta  = *mType.mDoublePtr - (double)rval;
        return delta >= -0.00001 && delta <= 0.00001;
      }
    case VARIANT_TYPE_DOUBLE:
      {
        double delta  = mType.mDouble - (double)rval;
        return delta >= -0.00001 && delta <= 0.00001;
      }

    case VARIANT_TYPE_LONG_DOUBLE_PTR:
      {
        long double delta  = *mType.mLDoublePtr - (long double)rval;
        return delta >= -0.00001 && delta <= 0.00001;
      }
    case VARIANT_TYPE_LONG_DOUBLE:
      {
        long double delta  = mType.mLDouble - (long double)rval;
        return delta >= -0.00001 && delta <= 0.00001;
      }

    case VARIANT_TYPE_CSTRING_PTR:
      return *(mType.mStr.Ptr) == (CString)rval;
      break;
    case VARIANT_TYPE_CSTRING:
      return *((CString *)mType.mStr.Raw) == (CString)rval;
      break;
  }
}

bool VariantType::operator!=(const VariantType &rval) const
{
  return !(*this == rval);
}

VariantType::operator bool(void) const
{
  switch(mFlags & VARIANT_TYPE)
  {
    default:
    case VARIANT_TYPE_NOT_SET:            return 0;
    case VARIANT_TYPE_VOID_PTR:           return  mType.mVoidPtr != 0;
    case VARIANT_TYPE_VOID:               return 0;
    case VARIANT_TYPE_BOOL_PTR:           return *mType.mBoolPtr;
    case VARIANT_TYPE_BOOL:               return  mType.mBool;
    case VARIANT_TYPE_CHAR_PTR:           return *mType.mCharPtr    != (char)          0;
    case VARIANT_TYPE_CHAR:               return  mType.mChar       != (char)          0;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR:  return *mType.mUCharPtr   != (unsigned char) 0;
    case VARIANT_TYPE_UNSIGNED_CHAR:      return  mType.mUChar      != (unsigned char) 0;
    case VARIANT_TYPE_SHORT_PTR:          return *mType.mShortPtr   != (short)         0;
    case VARIANT_TYPE_SHORT:              return  mType.mShort      != (short)         0;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR: return *mType.mUShortPtr  != (unsigned short)0;
    case VARIANT_TYPE_UNSIGNED_SHORT:     return  mType.mUShort     != (unsigned short)0;
    case VARIANT_TYPE_INT_PTR:            return *mType.mIntPtr     != (int)           0;
    case VARIANT_TYPE_INT:                return  mType.mInt        != (int)           0;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:   return *mType.mUIntPtr    != (unsigned int)  0;
    case VARIANT_TYPE_UNSIGNED_INT:       return  mType.mUInt       != (unsigned int)  0;
    case VARIANT_TYPE_LONG_PTR:           return *mType.mLongPtr    != (long)          0;
    case VARIANT_TYPE_LONG:               return  mType.mLong       != (long)          0;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR:  return *mType.mULongPtr   != (unsigned long) 0;
    case VARIANT_TYPE_UNSIGNED_LONG:      return  mType.mULong      != (unsigned long) 0;

    case VARIANT_TYPE_FLOAT_PTR:          return *mType.mFloatPtr   >=  0.00001f ||
                                                *mType.mFloatPtr   <= -0.00001f;
    case VARIANT_TYPE_FLOAT:              return  mType.mFloat      >=  0.00001f ||
                                                 mType.mFloat      <= -0.00001f;
    case VARIANT_TYPE_DOUBLE_PTR:         return *mType.mDoublePtr  >=  0.00001 ||
                                                *mType.mDoublePtr  <= -0.00001;
    case VARIANT_TYPE_DOUBLE:             return  mType.mDouble     >=  0.00001 ||
                                                 mType.mDouble     <= -0.00001;
    case VARIANT_TYPE_LONG_DOUBLE_PTR:    return *mType.mLDoublePtr >=  0.00001 ||
                                                *mType.mLDoublePtr <= -0.00001;
    case VARIANT_TYPE_LONG_DOUBLE:        return  mType.mLDouble    >=  0.00001 ||
                                                 mType.mLDouble    <= -0.00001;

    case VARIANT_TYPE_CSTRING_PTR:
      return mType.mStr.Ptr->size() != 0;
      break;
    case VARIANT_TYPE_CSTRING:
      return ((CString *)mType.mStr.Raw)->size() != 0;
      break;
  }
}

VariantType::operator void *(void) const
{
  switch(mFlags & VARIANT_TYPE)
  {
    default:
    case VARIANT_TYPE_NOT_SET:            return  0;
    case VARIANT_TYPE_VOID_PTR:           return  mType.mVoidPtr;
    case VARIANT_TYPE_VOID:               return  0;
    case VARIANT_TYPE_BOOL_PTR:           return  mType.mBoolPtr;
    case VARIANT_TYPE_BOOL:               return  0;
    case VARIANT_TYPE_CHAR_PTR:           return  mType.mCharPtr;
    case VARIANT_TYPE_CHAR:               return  0;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR:  return  mType.mUCharPtr;
    case VARIANT_TYPE_UNSIGNED_CHAR:      return  0;
    case VARIANT_TYPE_SHORT_PTR:          return  mType.mShortPtr;
    case VARIANT_TYPE_SHORT:              return  0;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR: return  mType.mUShortPtr;
    case VARIANT_TYPE_UNSIGNED_SHORT:     return  0;
    case VARIANT_TYPE_INT_PTR:            return  mType.mIntPtr;
    case VARIANT_TYPE_INT:                return  0;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:   return  mType.mUIntPtr;
    case VARIANT_TYPE_UNSIGNED_INT:       return  0;
    case VARIANT_TYPE_LONG_PTR:           return  mType.mLongPtr;
    case VARIANT_TYPE_LONG:               return  0;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR:  return  mType.mULongPtr;
    case VARIANT_TYPE_UNSIGNED_LONG:      return  0;
    case VARIANT_TYPE_FLOAT_PTR:          return  mType.mFloatPtr;
    case VARIANT_TYPE_FLOAT:              return  0;
    case VARIANT_TYPE_DOUBLE_PTR:         return  mType.mDoublePtr;
    case VARIANT_TYPE_DOUBLE:             return  0;
    case VARIANT_TYPE_LONG_DOUBLE_PTR:    return  mType.mLDoublePtr;
    case VARIANT_TYPE_LONG_DOUBLE:        return  0;

    case VARIANT_TYPE_CSTRING_PTR:        return  mType.mStr.Ptr;
    case VARIANT_TYPE_CSTRING:            return  0;
  }
}

OPERATOR_TYPE(unsigned char)
OPERATOR_TYPE(char)
OPERATOR_TYPE(unsigned short)
OPERATOR_TYPE(short)
OPERATOR_TYPE(unsigned int)
OPERATOR_TYPE(int)
OPERATOR_TYPE(unsigned long)
OPERATOR_TYPE(long)
OPERATOR_TYPE(float)
OPERATOR_TYPE(double)
OPERATOR_TYPE(long double)

OPERATOR_TYPE_PTR(bool *,           VARIANT_TYPE_BOOL_PTR)
OPERATOR_TYPE_PTR(unsigned char *,  VARIANT_TYPE_UNSIGNED_CHAR_PTR)

char *VariantType::GetCharPtr(void) const
{
  if((mFlags & VARIANT_TYPE_CHAR_PTR) == VARIANT_TYPE_CHAR_PTR)
    return (char *)(void *)*this;
  return 0;
}

OPERATOR_TYPE_PTR(unsigned short *, VARIANT_TYPE_UNSIGNED_SHORT_PTR)
OPERATOR_TYPE_PTR(short *,          VARIANT_TYPE_SHORT_PTR)
OPERATOR_TYPE_PTR(unsigned int *,   VARIANT_TYPE_UNSIGNED_INT_PTR)
OPERATOR_TYPE_PTR(int *,            VARIANT_TYPE_INT_PTR)
OPERATOR_TYPE_PTR(unsigned long *,  VARIANT_TYPE_UNSIGNED_LONG_PTR)
OPERATOR_TYPE_PTR(long *,           VARIANT_TYPE_LONG_PTR)
OPERATOR_TYPE_PTR(float *,          VARIANT_TYPE_FLOAT_PTR)
OPERATOR_TYPE_PTR(double *,         VARIANT_TYPE_DOUBLE_PTR)
OPERATOR_TYPE_PTR(long double *,    VARIANT_TYPE_LONG_DOUBLE_PTR)
OPERATOR_TYPE_PTR(CString *,        VARIANT_TYPE_CSTRING_PTR)

VariantType::operator CString(void) const
{
  switch(mFlags & VARIANT_TYPE)
  {
    default:
    case VARIANT_TYPE_NOT_SET:            return CString(0);
    case VARIANT_TYPE_VOID_PTR:           return CString(0);
    case VARIANT_TYPE_VOID:               return CString(0);
    case VARIANT_TYPE_BOOL_PTR:
      if(*mType.mBoolPtr)
        return CString("True");
      return CString("False");
    case VARIANT_TYPE_BOOL:
      if(mType.mBool)
        return CString("True");
      return CString("False");
    case VARIANT_TYPE_CHAR_PTR:           return OutputDec((long)*mType.mCharPtr);
    case VARIANT_TYPE_CHAR:               return OutputDec((long) mType.mChar);
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR:  return OutputDec((unsigned long)*mType.mUCharPtr);
    case VARIANT_TYPE_UNSIGNED_CHAR:      return OutputDec((unsigned long) mType.mUChar);
    case VARIANT_TYPE_SHORT_PTR:          return OutputDec((long)*mType.mShortPtr);
    case VARIANT_TYPE_SHORT:              return OutputDec((long) mType.mShort);
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR: return OutputDec((unsigned long)*mType.mUShortPtr);
    case VARIANT_TYPE_UNSIGNED_SHORT:     return OutputDec((unsigned long) mType.mUShort);
    case VARIANT_TYPE_INT_PTR:            return OutputDec((long)*mType.mIntPtr);
    case VARIANT_TYPE_INT:                return OutputDec((long) mType.mInt);
    case VARIANT_TYPE_UNSIGNED_INT_PTR:   return OutputDec((unsigned long)*mType.mUIntPtr);
    case VARIANT_TYPE_UNSIGNED_INT:       return OutputDec((unsigned long) mType.mUInt);
    case VARIANT_TYPE_LONG_PTR:           return OutputDec((long)*mType.mLongPtr);
    case VARIANT_TYPE_LONG:               return OutputDec((long) mType.mLong);
    case VARIANT_TYPE_UNSIGNED_LONG_PTR:  return OutputDec((unsigned long)*mType.mULongPtr);
    case VARIANT_TYPE_UNSIGNED_LONG:      return OutputDec((unsigned long) mType.mULong);
    case VARIANT_TYPE_FLOAT_PTR:
      {
        CString ret;
        ret.sprintf("%f", *mType.mFloatPtr);
        unsigned int i = ret.find_last_not_of('0');
        if(ret[i] == '.')
          ret.erase(i + 2, 10000);
        else
          ret.erase(i + 1, 10000);
        ret += "f";
        return ret;
      }
    case VARIANT_TYPE_FLOAT:
      {
        CString ret;
        ret.sprintf("%f", mType.mFloat);
        unsigned int i = ret.find_last_not_of('0');
        if(ret[i] == '.')
          ret.erase(i + 2, 10000);
        else
          ret.erase(i + 1, 10000);
        ret += "f";
        return ret;
      }
    case VARIANT_TYPE_DOUBLE_PTR:
      {
        CString ret;
        ret.sprintf("%f", *mType.mDoublePtr);
        unsigned int i = ret.find_last_not_of('0');
        if(ret[i] == '.')
          ret.erase(i + 2, 10000);
        else
          ret.erase(i + 1, 10000);
        return ret;
      }
    case VARIANT_TYPE_DOUBLE:
      {
        CString ret;
        ret.sprintf("%f", mType.mDouble);
        unsigned int i = ret.find_last_not_of('0');
        if(ret[i] == '.')
          ret.erase(i + 2, 10000);
        else
          ret.erase(i + 1, 10000);
        return ret;
      }
    case VARIANT_TYPE_LONG_DOUBLE_PTR:
      {
        CString ret;
        ret.sprintf("%Lf", *mType.mLDoublePtr);
        unsigned int i = ret.find_last_not_of('0');
        if(ret[i] == '.')
          ret.erase(i + 2, 10000);
        else
          ret.erase(i + 1, 10000);
        return ret;
      }
    case VARIANT_TYPE_LONG_DOUBLE:
      {
        CString ret;
        ret.sprintf("%Lf", mType.mLDouble);
        unsigned int i = ret.find_last_not_of('0');
        if(ret[i] == '.')
          ret.erase(i + 2, 10000);
        else
          ret.erase(i + 1, 10000);
        return ret;
      }

    case VARIANT_TYPE_CSTRING_PTR:        return *mType.mStr.Ptr;
    case VARIANT_TYPE_CSTRING:            return *((CString *)mType.mStr.Raw);
  }
}

VariantType &VariantType::ConvertTo(unsigned int type)
{
  type &= VARIANT_TYPE;
  switch(type)
  {
    default:
    case VARIANT_TYPE_NOT_SET:                                             break;
    case VARIANT_TYPE_VOID:          type = VARIANT_TYPE_NOT_SET;          break;
    case VARIANT_TYPE_BOOL:          mType.mBool   =(bool)          *this; break;
    case VARIANT_TYPE_CHAR:          mType.mChar   =(char)          *this; break;
    case VARIANT_TYPE_UNSIGNED_CHAR: mType.mUChar  =(unsigned char) *this; break;
    case VARIANT_TYPE_SHORT:         mType.mShort  =(short)         *this; break;
    case VARIANT_TYPE_UNSIGNED_SHORT:mType.mUShort =(unsigned short)*this; break;
    case VARIANT_TYPE_INT:           mType.mInt    =(int)           *this; break;
    case VARIANT_TYPE_UNSIGNED_INT:  mType.mUInt   =(unsigned int)  *this; break;
    case VARIANT_TYPE_LONG:          mType.mLong   =(long)          *this; break;
    case VARIANT_TYPE_UNSIGNED_LONG: mType.mULong  =(unsigned long) *this; break;
    case VARIANT_TYPE_FLOAT:         mType.mFloat  =(float)         *this; break;
    case VARIANT_TYPE_DOUBLE:        mType.mDouble =(double)        *this; break;
    case VARIANT_TYPE_LONG_DOUBLE:   mType.mLDouble=(long double)   *this; break;

    case VARIANT_TYPE_CSTRING:
      BuildString((CString)*this);
      return *this;
  }
  mFlags = (mFlags & VARIANT_DECIMAL_OUTPUT) | type;
  return *this;
}

VariantType &VariantType::SetValue_DontChangeType(const VariantType &rval)
{
  switch(mFlags & VARIANT_TYPE)
  {
    default:
    case VARIANT_TYPE_NOT_SET:                                                    break;
    case VARIANT_TYPE_VOID_PTR:           mType.mVoidPtr   = (void *)        rval;break;
    case VARIANT_TYPE_VOID:                                                       break;
    case VARIANT_TYPE_BOOL_PTR:          *mType.mBoolPtr   = (bool)          rval;break;
    case VARIANT_TYPE_BOOL:               mType.mBool      = (bool)          rval;break;
    case VARIANT_TYPE_CHAR_PTR:          *mType.mCharPtr   = (char)          rval;break;
    case VARIANT_TYPE_CHAR:               mType.mChar      = (char)          rval;break;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR: *mType.mUCharPtr  = (unsigned char) rval;break;
    case VARIANT_TYPE_UNSIGNED_CHAR:      mType.mUChar     = (unsigned char) rval;break;
    case VARIANT_TYPE_SHORT_PTR:         *mType.mShortPtr  = (short)         rval;break;
    case VARIANT_TYPE_SHORT:              mType.mShort     = (short)         rval;break;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR:*mType.mUShortPtr = (unsigned short)rval;break;
    case VARIANT_TYPE_UNSIGNED_SHORT:     mType.mUShort    = (unsigned short)rval;break;
    case VARIANT_TYPE_INT_PTR:           *mType.mIntPtr    = (int)           rval;break;
    case VARIANT_TYPE_INT:                mType.mInt       = (int)           rval;break;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:  *mType.mUIntPtr   = (unsigned int)  rval;break;
    case VARIANT_TYPE_UNSIGNED_INT:       mType.mUInt      = (unsigned int)  rval;break;
    case VARIANT_TYPE_LONG_PTR:          *mType.mLongPtr   = (long)          rval;break;
    case VARIANT_TYPE_LONG:               mType.mLong      = (long)          rval;break;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR: *mType.mULongPtr  = (unsigned long) rval;break;
    case VARIANT_TYPE_UNSIGNED_LONG:      mType.mULong     = (unsigned long) rval;break;
    case VARIANT_TYPE_FLOAT_PTR:         *mType.mFloatPtr  = (float)         rval;break;
    case VARIANT_TYPE_FLOAT:              mType.mFloat     = (float)         rval;break;
    case VARIANT_TYPE_DOUBLE_PTR:        *mType.mDoublePtr = (double)        rval;break;
    case VARIANT_TYPE_DOUBLE:             mType.mDouble    = (double)        rval;break;
    case VARIANT_TYPE_LONG_DOUBLE_PTR:   *mType.mLDoublePtr= (long double)   rval;break;
    case VARIANT_TYPE_LONG_DOUBLE:        mType.mLDouble   = (long double)   rval;break;

    case VARIANT_TYPE_CSTRING_PTR:
      *mType.mStr.Ptr = (CString)rval;
      break;
    case VARIANT_TYPE_CSTRING:
      *((CString *)mType.mStr.Raw) = (CString)rval;
      break;
  }

  return *this;
}

VariantType &VariantType::PopPointer(void)
{
  if(IsAPointer())
    ConvertTo((mFlags & VARIANT_TYPE) + 1);

  return *this;
}

bool VariantType::IsAPointer(void) const
{
  return mFlags & 0x01;
}

bool VariantType::IsBool(void) const
{
  unsigned int type = mFlags & VARIANT_TYPE;
  return type >= VARIANT_TYPE_BOOL_PTR && type <= VARIANT_TYPE_BOOL;
}

bool VariantType::IsNumeric(void) const
{
  unsigned int type = mFlags & VARIANT_TYPE;
  return type >= VARIANT_TYPE_UNSIGNED_CHAR_PTR && type <= VARIANT_TYPE_LONG_DOUBLE;
}

bool VariantType::IsDecimal(void) const
{
  unsigned int type = mFlags & VARIANT_TYPE;
  return type >= VARIANT_TYPE_UNSIGNED_CHAR_PTR && type <= VARIANT_TYPE_LONG;
}

bool VariantType::IsFloat(void) const
{
  unsigned int type = mFlags & VARIANT_TYPE;
  return type >= VARIANT_TYPE_FLOAT_PTR && type <= VARIANT_TYPE_LONG_DOUBLE;
}

bool VariantType::IsString(void) const
{
  unsigned int type = mFlags & VARIANT_TYPE;
  return type >= VARIANT_TYPE_CSTRING_PTR && type <= VARIANT_TYPE_CSTRING;
}

bool VariantType::IsSigned(void) const
{
  unsigned int type = mFlags & VARIANT_TYPE;
  switch(type)
  {
    case VARIANT_TYPE_CHAR_PTR:
    case VARIANT_TYPE_CHAR:
    case VARIANT_TYPE_SHORT_PTR:
    case VARIANT_TYPE_SHORT:
    case VARIANT_TYPE_INT_PTR:
    case VARIANT_TYPE_INT:
    case VARIANT_TYPE_LONG_PTR:
    case VARIANT_TYPE_LONG:
    case VARIANT_TYPE_FLOAT_PTR:
    case VARIANT_TYPE_FLOAT:
    case VARIANT_TYPE_DOUBLE_PTR:
    case VARIANT_TYPE_DOUBLE:
    case VARIANT_TYPE_LONG_DOUBLE_PTR:
    case VARIANT_TYPE_LONG_DOUBLE:
      return 1;
  }
  return 0;
}

bool VariantType::IsNegative(void) const
{
  return IsSigned() && (float)*this < 0.0f;
}

unsigned char VariantType::GetType(void) const
{
  return mFlags & VARIANT_TYPE;
}

CString VariantType::GetTypeString(void) const
{
  return GetTypeString(mFlags);
}

CString VariantType::GetTypeString(unsigned char flags) const
{
  switch(flags & VARIANT_TYPE)
  {
    default:                             return "Corrupted VariantType";
    case VARIANT_TYPE_NOT_SET:           return "Type Not Set";
    case VARIANT_TYPE_VOID_PTR:          return "void *";
    case VARIANT_TYPE_VOID:              return "void";
    case VARIANT_TYPE_BOOL_PTR:          return "bool *";
    case VARIANT_TYPE_BOOL:              return "bool";
    case VARIANT_TYPE_CHAR_PTR:          return "char *";
    case VARIANT_TYPE_CHAR:              return "char";
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR: return "unsigned char *";
    case VARIANT_TYPE_UNSIGNED_CHAR:     return "unsigned char";
    case VARIANT_TYPE_SHORT_PTR:         return "short *";
    case VARIANT_TYPE_SHORT:             return "short";
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR:return "unsigned short *";
    case VARIANT_TYPE_UNSIGNED_SHORT:    return "unsigned short";
    case VARIANT_TYPE_INT_PTR:           return "int *";
    case VARIANT_TYPE_INT:               return "int";
    case VARIANT_TYPE_UNSIGNED_INT_PTR:  return "unsigned int *";
    case VARIANT_TYPE_UNSIGNED_INT:      return "unsigned int";
    case VARIANT_TYPE_LONG_PTR:          return "long *";
    case VARIANT_TYPE_LONG:              return "long";
    case VARIANT_TYPE_UNSIGNED_LONG_PTR: return "unsigned long *";
    case VARIANT_TYPE_UNSIGNED_LONG:     return "unsigned long";
    case VARIANT_TYPE_FLOAT_PTR:         return "float *";
    case VARIANT_TYPE_FLOAT:             return "float";
    case VARIANT_TYPE_DOUBLE_PTR:        return "double *";
    case VARIANT_TYPE_DOUBLE:            return "double";
    case VARIANT_TYPE_LONG_DOUBLE_PTR:   return "long double *";
    case VARIANT_TYPE_LONG_DOUBLE:       return "long double";
    case VARIANT_TYPE_CSTRING_PTR:       return "CString *";
    case VARIANT_TYPE_CSTRING:           return "CString";
  }
}

void VariantType::SetDecimalOutput(unsigned int type)
{
  mFlags = (mFlags & VARIANT_TYPE) | (type & VARIANT_DECIMAL_OUTPUT);
}

CVector<unsigned char> VariantType::Pack(void) const
{
  CVector<unsigned char> data;
  return Pack(data);
}

CVector<unsigned char> &VariantType::Pack(CVector<unsigned char> &data) const
{
  unsigned int i;
  bool writesize = 0;
  unsigned int size = 0;
  unsigned char *val = 0;

  data.push_back(mFlags);
  switch(mFlags & VARIANT_TYPE)
  {
    case VARIANT_TYPE_NOT_SET:                                                                                       break;
    case VARIANT_TYPE_VOID_PTR:          val = (unsigned char *)&mType.mVoidPtr   ; size = sizeof(mType.mVoidPtr   );break;
    case VARIANT_TYPE_VOID:                                                                                          break;
    case VARIANT_TYPE_BOOL_PTR:          val = (unsigned char *)&mType.mBoolPtr   ; size = sizeof(mType.mBoolPtr   );break;
    case VARIANT_TYPE_BOOL:              val = (unsigned char *)&mType.mBool      ; size = sizeof(mType.mBool      );break;
    case VARIANT_TYPE_CHAR_PTR:          val = (unsigned char *)&mType.mCharPtr   ; size = sizeof(mType.mCharPtr   );break;
    case VARIANT_TYPE_CHAR:              val = (unsigned char *)&mType.mChar      ; size = sizeof(mType.mChar      );break;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR: val = (unsigned char *)&mType.mUCharPtr  ; size = sizeof(mType.mUCharPtr  );break;
    case VARIANT_TYPE_UNSIGNED_CHAR:     val = (unsigned char *)&mType.mUChar     ; size = sizeof(mType.mUChar     );break;
    case VARIANT_TYPE_SHORT_PTR:         val = (unsigned char *)&mType.mShortPtr  ; size = sizeof(mType.mShortPtr  );break;
    case VARIANT_TYPE_SHORT:             val = (unsigned char *)&mType.mShort     ; size = sizeof(mType.mShort     );break;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR:val = (unsigned char *)&mType.mUShortPtr ; size = sizeof(mType.mUShortPtr );break;
    case VARIANT_TYPE_UNSIGNED_SHORT:    val = (unsigned char *)&mType.mUShort    ; size = sizeof(mType.mUShort    );break;
    case VARIANT_TYPE_INT_PTR:           val = (unsigned char *)&mType.mIntPtr    ; size = sizeof(mType.mIntPtr    );break;
    case VARIANT_TYPE_INT:               val = (unsigned char *)&mType.mInt       ; size = sizeof(mType.mInt       );break;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:  val = (unsigned char *)&mType.mUIntPtr   ; size = sizeof(mType.mUIntPtr   );break;
    case VARIANT_TYPE_UNSIGNED_INT:      val = (unsigned char *)&mType.mUInt      ; size = sizeof(mType.mUInt      );break;
    case VARIANT_TYPE_LONG_PTR:          val = (unsigned char *)&mType.mLongPtr   ; size = sizeof(mType.mLongPtr   );break;
    case VARIANT_TYPE_LONG:              val = (unsigned char *)&mType.mLong      ; size = sizeof(mType.mLong      );break;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR: val = (unsigned char *)&mType.mULongPtr  ; size = sizeof(mType.mULongPtr  );break;
    case VARIANT_TYPE_UNSIGNED_LONG:     val = (unsigned char *)&mType.mULong     ; size = sizeof(mType.mULong     );break;
    case VARIANT_TYPE_FLOAT_PTR:         val = (unsigned char *)&mType.mFloatPtr  ; size = sizeof(mType.mFloatPtr  );break;
    case VARIANT_TYPE_FLOAT:             val = (unsigned char *)&mType.mFloat     ; size = sizeof(mType.mFloat     );break;
    case VARIANT_TYPE_DOUBLE_PTR:        val = (unsigned char *)&mType.mDoublePtr ; size = sizeof(mType.mDoublePtr );break;
    case VARIANT_TYPE_DOUBLE:            val = (unsigned char *)&mType.mDouble    ; size = sizeof(mType.mDouble    );break;
    case VARIANT_TYPE_LONG_DOUBLE_PTR:   val = (unsigned char *)&mType.mLDoublePtr; size = sizeof(mType.mLDoublePtr);break;
    case VARIANT_TYPE_LONG_DOUBLE:       val = (unsigned char *)&mType.mLDouble   ; size = sizeof(mType.mLDouble   );break;

    case VARIANT_TYPE_CSTRING_PTR:
      val = (unsigned char *)&mType.mStr.Ptr; size = sizeof(mType.mStr.Ptr);
      break;
    case VARIANT_TYPE_CSTRING:
      val = (unsigned char *)((CString *)mType.mStr.Raw)->c_str(); size = ((CString *)mType.mStr.Raw)->size();
      writesize = 1;
      break;
  }

  if(writesize)
    for(i = 0; i < sizeof(size); ++i)
      data.push_back(((unsigned char *)&size)[i]);

  for(i = 0; i < size; ++i)
    data.push_back(val[i]);

  return data;
}

unsigned int VariantType::Unpack(const CVector<unsigned char> &data, unsigned int start)
{
  unsigned int i;
  bool writesize = 0;
  unsigned int size = 0;
  unsigned char *val = 0;

  DestroyString();
  if(start >= data.size())
    return start;

  mFlags = data[start++];

  switch(mFlags & VARIANT_TYPE)
  {
    case VARIANT_TYPE_NOT_SET:                                                                                       break;
    case VARIANT_TYPE_VOID_PTR:          val = (unsigned char *)&mType.mVoidPtr   ; size = sizeof(mType.mVoidPtr   );break;
    case VARIANT_TYPE_VOID:                                                                                          break;
    case VARIANT_TYPE_BOOL_PTR:          val = (unsigned char *)&mType.mBoolPtr   ; size = sizeof(mType.mBoolPtr   );break;
    case VARIANT_TYPE_BOOL:              val = (unsigned char *)&mType.mBool      ; size = sizeof(mType.mBool      );break;
    case VARIANT_TYPE_CHAR_PTR:          val = (unsigned char *)&mType.mCharPtr   ; size = sizeof(mType.mCharPtr   );break;
    case VARIANT_TYPE_CHAR:              val = (unsigned char *)&mType.mChar      ; size = sizeof(mType.mChar      );break;
    case VARIANT_TYPE_UNSIGNED_CHAR_PTR: val = (unsigned char *)&mType.mUCharPtr  ; size = sizeof(mType.mUCharPtr  );break;
    case VARIANT_TYPE_UNSIGNED_CHAR:     val = (unsigned char *)&mType.mUChar     ; size = sizeof(mType.mUChar     );break;
    case VARIANT_TYPE_SHORT_PTR:         val = (unsigned char *)&mType.mShortPtr  ; size = sizeof(mType.mShortPtr  );break;
    case VARIANT_TYPE_SHORT:             val = (unsigned char *)&mType.mShort     ; size = sizeof(mType.mShort     );break;
    case VARIANT_TYPE_UNSIGNED_SHORT_PTR:val = (unsigned char *)&mType.mUShortPtr ; size = sizeof(mType.mUShortPtr );break;
    case VARIANT_TYPE_UNSIGNED_SHORT:    val = (unsigned char *)&mType.mUShort    ; size = sizeof(mType.mUShort    );break;
    case VARIANT_TYPE_INT_PTR:           val = (unsigned char *)&mType.mIntPtr    ; size = sizeof(mType.mIntPtr    );break;
    case VARIANT_TYPE_INT:               val = (unsigned char *)&mType.mInt       ; size = sizeof(mType.mInt       );break;
    case VARIANT_TYPE_UNSIGNED_INT_PTR:  val = (unsigned char *)&mType.mUIntPtr   ; size = sizeof(mType.mUIntPtr   );break;
    case VARIANT_TYPE_UNSIGNED_INT:      val = (unsigned char *)&mType.mUInt      ; size = sizeof(mType.mUInt      );break;
    case VARIANT_TYPE_LONG_PTR:          val = (unsigned char *)&mType.mLongPtr   ; size = sizeof(mType.mLongPtr   );break;
    case VARIANT_TYPE_LONG:              val = (unsigned char *)&mType.mLong      ; size = sizeof(mType.mLong      );break;
    case VARIANT_TYPE_UNSIGNED_LONG_PTR: val = (unsigned char *)&mType.mULongPtr  ; size = sizeof(mType.mULongPtr  );break;
    case VARIANT_TYPE_UNSIGNED_LONG:     val = (unsigned char *)&mType.mULong     ; size = sizeof(mType.mULong     );break;
    case VARIANT_TYPE_FLOAT_PTR:         val = (unsigned char *)&mType.mFloatPtr  ; size = sizeof(mType.mFloatPtr  );break;
    case VARIANT_TYPE_FLOAT:             val = (unsigned char *)&mType.mFloat     ; size = sizeof(mType.mFloat     );break;
    case VARIANT_TYPE_DOUBLE_PTR:        val = (unsigned char *)&mType.mDoublePtr ; size = sizeof(mType.mDoublePtr );break;
    case VARIANT_TYPE_DOUBLE:            val = (unsigned char *)&mType.mDouble    ; size = sizeof(mType.mDouble    );break;
    case VARIANT_TYPE_LONG_DOUBLE_PTR:   val = (unsigned char *)&mType.mLDoublePtr; size = sizeof(mType.mLDoublePtr);break;
    case VARIANT_TYPE_LONG_DOUBLE:       val = (unsigned char *)&mType.mLDouble   ; size = sizeof(mType.mLDouble   );break;

    case VARIANT_TYPE_CSTRING_PTR:
      val = (unsigned char *)&mType.mStr.Ptr; size = sizeof(mType.mStr.Ptr);
      break;
    case VARIANT_TYPE_CSTRING:
      writesize = 1;
      break;

    case VARIANT_TYPE_NAMED_VARIANT:
      mFlags = 0;
      start = Unpack(data, start); // Discard the name
      return Unpack(data, start);
  }

  if(writesize)
  {
    for(i = 0; i < sizeof(size); ++i)
      ((unsigned char *)&size)[i] = data.mData[start++];
    if(start + size > data.size())
    {
      DestroyString();
      return start;
    }

    mFlags = 0;
    BuildString(CString(size, 0));
    val = (unsigned char *)((CString *)mType.mStr.Raw)->c_str();
  }

  if(start + size <= data.size())
    for(i = 0; i < size; ++i)
      val[i] = data.mData[start++];
  else
  {
    DestroyString();
    return data.size();
  }

  return start;
}

unsigned char VariantType::UnpackType(const CVector<unsigned char> &data, unsigned int start)
{
  unsigned char type;

  if(start >= data.size())
    return VARIANT_TYPE_NOT_SET;

  type = data[start] & VARIANT_TYPE;

  if(VARIANT_TYPE_NAMED_VARIANT)
  {
    start = VariantType().Unpack(data, start); // Discard the name
    return UnpackType(data, start);
  }

  return type;
}

CString VariantType::UnpackTypeString(const CVector<unsigned char> &data, unsigned int start)
{
  return GetTypeString(UnpackType(data, start));
}

void VariantType::Print(void) const
{
  CString type = GetTypeString();
  if(type.size() && type[type.size() - 1] != '*')
    type += "  ";
  printf("%16s: %s\n", type.c_str(), ((CString)*this).c_str());
}

void VariantType::BuildString(const CString &val)
{
  new (mType.mStr.Raw) CString(val);
  mType.mStr.Ptr = 0;
  mFlags = (mFlags & VARIANT_DECIMAL_OUTPUT) | VARIANT_TYPE_CSTRING;
}

void VariantType::BuildString(CString *val)
{
  DestroyString();

  mType.mStr.Ptr = val;
  mFlags = (mFlags & VARIANT_DECIMAL_OUTPUT) | VARIANT_TYPE_CSTRING_PTR;
}

void VariantType::DestroyString(void)
{
  if(mFlags == VARIANT_TYPE_CSTRING)
    ((CString *)mType.mStr.Raw)->~CString();

  mFlags &= VARIANT_DECIMAL_OUTPUT;
}

CString VariantType::OutputDec(long val) const
{
  CString ret;

  if(val >= 0)
    return OutputDec((unsigned long)val);

  if((mFlags & VARIANT_DECIMAL_OUTPUT) == VARIANT_DECIMAL_OUTPUT_OCTAL)
    ret.sprintf("-%#o", -val);
  else
  if((mFlags & VARIANT_DECIMAL_OUTPUT) == VARIANT_DECIMAL_OUTPUT_HEX)
    ret.sprintf("%ld", val);
  else
    ret.sprintf("%ld", val);

  return ret;
}

CString VariantType::OutputDec(unsigned long val) const
{
  CString ret;

  if((mFlags & VARIANT_DECIMAL_OUTPUT) == VARIANT_DECIMAL_OUTPUT_BINARY)
  {
    unsigned int high = 0;
    unsigned int i;

    for(i = 0; i < sizeof(val) * 8; ++i)
      if(val & (1 << i))
        high = i;

    ret += "0b";
    for(i = high; i != ~(unsigned int)0; --i)
      if(val & (1 << i))
        ret += '1';
      else
        ret += '0';
  }
  else
  if((mFlags & VARIANT_DECIMAL_OUTPUT) == VARIANT_DECIMAL_OUTPUT_OCTAL)
    ret.sprintf("%#o", val);
  else
  if((mFlags & VARIANT_DECIMAL_OUTPUT) == VARIANT_DECIMAL_OUTPUT_HEX)
    ret.sprintf("0x%X", val);
  else
    ret.sprintf("%lu", val);

  return ret;
}

#define VARIANT_TYPE_AUTO_CONVERT(T)                                               \
VariantType operator+(T va, const VariantType &var){return VariantType(va) + var;} \
VariantType operator-(T va, const VariantType &var){return VariantType(va) - var;} \
VariantType operator*(T va, const VariantType &var){return VariantType(va) * var;} \
VariantType operator/(T va, const VariantType &var){return VariantType(va) / var;} \
VariantType operator+(const VariantType &var, T va){return var + VariantType(va);} \
VariantType operator-(const VariantType &var, T va){return var - VariantType(va);} \
VariantType operator*(const VariantType &var, T va){return var * VariantType(va);} \
VariantType operator/(const VariantType &var, T va){return var / VariantType(va);} \
bool operator< (const VariantType &var, T va){return var <  VariantType(va);}      \
bool operator> (const VariantType &var, T va){return var >  VariantType(va);}      \
bool operator<=(const VariantType &var, T va){return var <= VariantType(va);}      \
bool operator>=(const VariantType &var, T va){return var >= VariantType(va);}      \
bool operator==(const VariantType &var, T va){return var == VariantType(va);}      \
bool operator!=(const VariantType &var, T va){return var != VariantType(va);}      \
bool operator< (T va, const VariantType &var){return VariantType(va) <  var;}      \
bool operator> (T va, const VariantType &var){return VariantType(va) >  var;}      \
bool operator<=(T va, const VariantType &var){return VariantType(va) <= var;}      \
bool operator>=(T va, const VariantType &var){return VariantType(va) >= var;}      \
bool operator==(T va, const VariantType &var){return VariantType(va) == var;}      \
bool operator!=(T va, const VariantType &var){return VariantType(va) != var;}

VARIANT_TYPE_AUTO_CONVERT(bool)
VARIANT_TYPE_AUTO_CONVERT(unsigned char)
VARIANT_TYPE_AUTO_CONVERT(char)
VARIANT_TYPE_AUTO_CONVERT(unsigned short)
VARIANT_TYPE_AUTO_CONVERT(short)
VARIANT_TYPE_AUTO_CONVERT(unsigned int)
VARIANT_TYPE_AUTO_CONVERT(int)
VARIANT_TYPE_AUTO_CONVERT(unsigned long)
VARIANT_TYPE_AUTO_CONVERT(long)
VARIANT_TYPE_AUTO_CONVERT(float)
VARIANT_TYPE_AUTO_CONVERT(double)
VARIANT_TYPE_AUTO_CONVERT(long double)
VARIANT_TYPE_AUTO_CONVERT(const CString &)
